package org.stvd.controller.workflow;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.activiti.engine.IdentityService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.delegate.Expression;
import org.activiti.engine.impl.pvm.PvmActivity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.task.TaskDefinition;
import org.activiti.engine.task.Task;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.stvd.common.Consts;
import org.stvd.common.DepAndUserHolder;
import org.stvd.common.aspectj.lang.annotation.Log;
import org.stvd.common.aspectj.lang.enums.BusinessType;
import org.stvd.common.security.SecurityUserHolder;
import org.stvd.common.utils.InterfaceResult;
import org.stvd.common.utils.ServiceResult;
import org.stvd.common.workflow.WorkflowConsts;
import org.stvd.controller.BaseController;
import org.stvd.core.util.StringUtil;
import org.stvd.entities.admin.Users;
import org.stvd.entities.workflow.WfGroup;
import org.stvd.entities.workflow.WfIndex;
import org.stvd.entities.workflow.WfUser;
import org.stvd.service.workflow.ProcessCoreService;
import org.stvd.service.workflow.WfGroupService;
import org.stvd.service.workflow.WfIndexService;
import org.stvd.service.workflow.WfLogsService;
import org.stvd.service.workflow.WfUserService;

/**
 * @Title ApproveBaseController
 * @Destribution 工作流审批抽象类
 * @author houzx
 * @date 2020年10月27日
 */
@Controller
public abstract class ApproveBaseController<T> extends BaseController {

    @Autowired
    WfIndexService wfIndexService;
    @Autowired
    WfLogsService wfLogsService;
    @Autowired
    TaskService taskService;
    @Autowired
    RuntimeService runtimeService;
    @Autowired
    IdentityService identityService;
    @Autowired
    private ProcessCoreService processCoreService;
    @Autowired
    private WfGroupService wfGroupService;
    @Autowired
    private WfUserService wfUserService;

    private Logger logger = LoggerFactory.getLogger("workflow");

    private String processDefinitionKey = "";

    public void setProcessDefinitionKey(String processDefinitionKey) {
        this.processDefinitionKey = processDefinitionKey;
    }

    /**
     * 加载列表页面所需数据
     */
    protected abstract String loadPageManageData(T entity);

    /**
     * 加载签收页面所需的数据
     */
    protected abstract String loadPageClaimData(String processInstanceId, String taskId);

    /**
     * 加载审批页面所需的数据
     */
    protected abstract String loadPageApproveData(Task task);

    /**
     * 加载跳转页面所需的数据
     */
    protected abstract String loadPageJumpData(Task task);

    /**
     * 节点办理，签收
     */
    protected abstract ServiceResult<Map<String, Object>> handlerClaim(String processInstanceId, String taskId,
            Map<String, Object> variables);

    /**
     * 节点办理，驳回
     */
    protected abstract ServiceResult<Map<String, Object>> handlerRefuse(String processInstanceId, String taskId,
            String jumpTaskKey, Map<String, Object> variables);

    /**
     * 
     * @param processInstanceId
     * @param userAssignee
     * @param jumpTaskKey
     * @return
     */
    protected abstract String loadActivityData(String processInstanceId, String jumpTaskKey);

    /**
     * 节点办理，通过
     */
    protected abstract ServiceResult<Map<String, Object>> handlerPass(String processInstanceId, String taskId,
            Map<String, Object> variables);

    /**
     * 节点办理，跳转
     */
    protected abstract ServiceResult<Map<String, Object>> handlerJump(String processInstanceId, String taskId,
            String jumpTaskKey, Map<String, Object> variables);

    /**
     * 流程详情
     */
    protected abstract String processDetail(String processInstanceId);

    @RequestMapping(value = "manage")
    public String onPageManage(@ModelAttribute("entity") T entity) throws Exception {
        String path = loadPageManageData(entity);
        return StringUtil.isEmpty(path) ? "Manage.html" : path;
    }

    /**
     * @Destribution 审批签收
     * @param processInstanceId
     * @param taskId
     * @return
     * @throws Exception
     */
    @GetMapping(value = "claim/{processInstanceId}/{taskId}")
    public String claimPageLoad(@PathVariable String processInstanceId, @PathVariable String taskId) {
        map.put("processInstanceId", processInstanceId);
        map.put("taskId", taskId);
        map.put("logList", wfLogsService.findByProcInstId(processInstanceId));
        String path = loadPageClaimData(processInstanceId, taskId);
        return StringUtil.isEmpty(path) ? "Claim.html" : path;
    }

    @Log(title = "审批业务签收", businessType = BusinessType.UPDATE)
    @PostMapping(value = "claim")
    @ResponseBody
    public InterfaceResult<T> onPageClaimAction(String processInstanceId, String taskId) {
        InterfaceResult<T> result = new InterfaceResult<T>();
        Map<String, Object> variables = new HashMap<String, Object>();
        variables.put(WorkflowConsts.INDEX_USER_ID, SecurityUserHolder.getCurrentUserId());
        variables.put(WorkflowConsts.INDEX_USER_NAME, SecurityUserHolder.getCurrentUserInfo().getUname());
        try {
            Task task = processCoreService.findTaskById(taskId);
            if (task != null) {
                variables.put("curr_task_key", task.getTaskDefinitionKey());
            }
            ServiceResult<Map<String, Object>> serviceResult = handlerClaim(processInstanceId, taskId, variables);
            if (serviceResult.isSuccess()) {
                processCoreService.transferAssignee(taskId, SecurityUserHolder.getCurrentUserId(), variables);
                result.setMsg("签收成功！");
            } else {
                result.setMsg("签收失败！失败原因：" + serviceResult.getMessage());
            }
        } catch (Exception ex) {
            result.setError("签收异常！异常原因：" + ex.getMessage());
            logger.error("签收异常！异常原因：" + ex.getMessage());
        }
        map.clear();
        return result;
    }

    /**
     * @Destribution 审批办理
     * @param processInstanceId
     * @param taskId
     * @return
     * @throws Exception
     */
    @GetMapping(value = "approve/{processInstanceId}/{taskId}")
    public String approvePageLoad(@PathVariable String processInstanceId, @PathVariable String taskId) {
        try {
            ActivityImpl activityImpl = processCoreService.findActivitiImpl(taskId, null);
            Task task = processCoreService.findTaskById(taskId);
            if (task != null && activityImpl != null) {
                map.put("processInstanceId", processInstanceId);
                map.put("taskId", taskId);
                map.put("logList", wfLogsService.findByProcInstId(processInstanceId));
                List<ActivityImpl> nextTaskList = processCoreService.getNextTaskInfo(activityImpl);
                List<PvmTransition> nextPvmList = processCoreService.getNextTaskInPvm(nextTaskList, activityImpl);
                map.put("nextPvmList", nextPvmList);

                List<TaskDefinition> nextTaskDefinitionList = processCoreService.getNextTaskDefinitionList(activityImpl,
                        taskId);
                if (nextTaskDefinitionList != null) {
                    List<Map<String, Object>> nextTaskDefList = new ArrayList<>();
                    Map<String, Object> taskMap = null;
                    for (TaskDefinition taskDefinition : nextTaskDefinitionList) {
                        taskMap = new HashMap<>();
                        taskMap.put(taskDefinition.getKey(), taskDefinition.getNameExpression());
                        Set<Expression> setMap = taskDefinition.getCandidateGroupIdExpressions();
                        if (setMap != null && setMap.size() > 0) {
                            String userGroups = "";
                            String userGroupsName = "";
                            for (Expression expression : setMap) {
                                String id = expression.getExpressionText();
                                userGroups += expression.getExpressionText() + " ";
                                WfGroup wfGroup = wfGroupService.findByPk(WfGroup.class,
                                        Long.valueOf(expression.getExpressionText()));
                                if (wfGroup != null) {
                                    userGroupsName = wfGroup.getName();
                                }
                            }
                            taskMap.put(taskDefinition.getKey() + "userGroups", userGroups);
                            taskMap.put(taskDefinition.getKey() + "userGroupsName", userGroupsName);
                        }
                        setMap = taskDefinition.getCandidateUserIdExpressions();
                        if (setMap != null && setMap.size() > 0) {
                            String UserIds = "";
                            String userNames = "";
                            for (Expression expression : setMap) {
                                UserIds += expression.getExpressionText() + " ";
                                WfUser wfUser = wfUserService.getWfUserByUid(expression.getExpressionText());
                                if (wfUser != null) {
                                    userNames = wfUser.getUserName();
                                }
                            }
                            taskMap.put(taskDefinition.getKey() + "UserIds", UserIds);
                            taskMap.put(taskDefinition.getKey() + "userNames", userNames);
                        }
                        nextTaskDefList.add(taskMap);
                        taskMap = null;
                    }
                    map.put("nextTaskDefList", nextTaskDefList);
                }

                if (StringUtil.isEmpty(task.getDescription()) || !task.getDescription().equals("no_refuse")) { // 禁止驳回
                    map.put("histTaskList", processCoreService.findBackAvtivity(taskId, activityImpl, nextTaskList));
                }

                String path = loadPageApproveData(task);
                if (StringUtil.isEmpty(path)) {
                    if (!StringUtil.isEmpty(task.getFormKey())) {
                        return task.getFormKey();
                    } else {
                        return task.getTaskDefinitionKey() + ".html";
                    }
                } else {
                    return path;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "Approve.html";
    }

    @Log(title = "审批业务办理", businessType = BusinessType.UPDATE)
    @PostMapping(value = "approve")
    @ResponseBody
    public InterfaceResult<Map<String, Object>> completeAction(String processInstanceId, String taskId)
            throws Exception {
        InterfaceResult<Map<String, Object>> result = new InterfaceResult<Map<String, Object>>();
        String operateType = request.getParameter(WorkflowConsts.INDEX_OPERATE_TYPE);
        if (StringUtil.isEmpty(operateType)) {
            result.setError("请选择处理结果！");
            return result;
        }
        Map<String, Object> variables = new HashMap<String, Object>();
        if (operateType.startsWith(WorkflowConsts.HANDLER_REFUSE + ":")) {
            String jumpTaskKey = request.getParameter(WorkflowConsts.JUMP_TASK_KEY);
            if (StringUtil.isEmpty(jumpTaskKey)) {
                result.setError("请选择要驳回到的节点！");
                return result;
            }
            variables.put(WorkflowConsts.INDEX_USER_ID, SecurityUserHolder.getCurrentUserId());
            variables.put(WorkflowConsts.INDEX_USER_NAME, SecurityUserHolder.getCurrentUserInfo().getUname());
            Enumeration<String> enu = request.getParameterNames();
            while (enu.hasMoreElements()) {
                String paraName = (String) enu.nextElement();
                if (request.getParameterValues(paraName).length > 1) {
                    variables.put(paraName, request.getParameterValues(paraName));
                } else {
                    variables.put(paraName, request.getParameter(paraName));
                }
            }
            ServiceResult<Map<String, Object>> serviceResult = handlerRefuse(processInstanceId, taskId, jumpTaskKey,
                    variables);
            if (serviceResult.isSuccess()) {
                processCoreService.backProcess(taskId, jumpTaskKey, variables);
                result.setMsg("审批完成！");
            } else {
                result.setError("审批提交失败！失败原因：" + serviceResult.getMessage());
            }
            WfIndex wfIndex = wfIndexService.findByProcInstId(processInstanceId);
            if (wfIndex != null) {
                String assiage = loadActivityData(processInstanceId, jumpTaskKey);
                if (!StringUtil.isEmpty(assiage)) {
                    wfIndex.setAssignee(assiage);
                    wfIndexService.update(wfIndex);
                }
            }

        } else if (operateType.startsWith(WorkflowConsts.HANDLER_PASS + ":")) {
            variables.put(WorkflowConsts.INDEX_USER_ID, SecurityUserHolder.getCurrentUserId());
            variables.put(WorkflowConsts.INDEX_USER_NAME, SecurityUserHolder.getCurrentUserInfo().getUname());
            Enumeration<String> enu = request.getParameterNames();
            while (enu.hasMoreElements()) {
                String paraName = (String) enu.nextElement();
                if (request.getParameterValues(paraName).length > 1) {
                    variables.put(paraName, request.getParameterValues(paraName));
                } else {
                    variables.put(paraName, request.getParameter(paraName));
                }
            }
            ServiceResult<Map<String, Object>> serviceResult = handlerPass(processInstanceId, taskId, variables);
            if (serviceResult.isSuccess()) {
                // 变更下一节点接收人人
                String nextTaskUser = request.getParameter("nextTaskUser");
                if (!StringUtil.isEmpty(nextTaskUser)) {
                    nextTaskUser = nextTaskUser.trim();
                }

                WfIndex wIndex = wfIndexService.findByProcInstId(processInstanceId);
                if (wIndex != null) {
                    if (nextTaskUser != null && !"".equals(nextTaskUser)) {
                        wIndex.setCandidate(nextTaskUser);
                    }
                    String assignee = "";
                    // 当前登录用户的最高机构ID
                    Map<String, Object> dataResult = DepAndUserHolder
                            .getApproveUserInfo(SecurityUserHolder.getCurrentUserId(), Consts.GUID);
                    if (dataResult != null && dataResult.size() > 0) {
                        Users user = (Users) dataResult.get("approveLeader");
                        if (user == null) {
                            user = (Users) dataResult.get("approveManage");
                        }
                        if (user != null) {
                            assignee = user.getUserId();
                        }
                    }
                    wIndex.setAssignee(assignee);
                    wfIndexService.update(wIndex);
                }

                processCoreService.passProcess(taskId, variables);
                result.setMsg("审批完成！");
            } else {
                result.setError("审批提交失败！失败原因：" + serviceResult.getMessage());
            }
        }
        map.clear();
        return result;
    }

    /**
     * @Destribution 审批流程跳转
     * @param processInstanceId
     * @param taskId
     * @return
     * @throws Exception
     */
    @GetMapping(value = "jump")
    public String skipPageLoad(String processInstanceId, String taskId) throws Exception {
        ActivityImpl activityImpl = processCoreService.findActivitiImpl(taskId, null);
        Task task = processCoreService.findTaskById(taskId);
        if (task != null && activityImpl != null) {
            List<ActivityImpl> nextAllTaskList = nextAllTaskDefinition(activityImpl, activityImpl.getId());
            map.put("processInstanceId", processInstanceId);
            map.put("logList", wfLogsService.findByProcInstId(processInstanceId));
            map.put("skipTaskList", nextAllTaskList);
            String path = loadPageJumpData(task);
            if (StringUtil.isEmpty(path)) {
                if (!StringUtil.isEmpty(task.getFormKey())) {
                    return task.getFormKey();
                } else {
                    return task.getTaskDefinitionKey() + ".html";
                }
            } else {
                return path;
            }
        }
        return "Jump.html";
    }

    @Log(title = "审批业务跳转", businessType = BusinessType.UPDATE)
    @PostMapping(value = "jump")
    @ResponseBody
    public InterfaceResult<Map<String, Object>> onworkflowSkipPageAction(String processInstanceId, String taskId)
            throws Exception {
        InterfaceResult<Map<String, Object>> result = new InterfaceResult<Map<String, Object>>();
        Map<String, Object> variables = new HashMap<String, Object>();
        String jumpTaskKey = request.getParameter(WorkflowConsts.SKIP_TASK_KEY);
        if (StringUtil.isEmpty(jumpTaskKey)) {
            result.setError("请选择要跳转到的节点！");
            return result;
        }
        variables.put(WorkflowConsts.INDEX_USER_ID, SecurityUserHolder.getCurrentUserId());
        variables.put(WorkflowConsts.INDEX_USER_NAME, SecurityUserHolder.getCurrentUserInfo().getUname());
        Enumeration<String> enu = request.getParameterNames();
        while (enu.hasMoreElements()) {
            String paraName = (String) enu.nextElement();
            if (request.getParameterValues(paraName).length > 1) {
                variables.put(paraName, request.getParameterValues(paraName));
            } else {
                variables.put(paraName, request.getParameter(paraName));
            }
        }
        ServiceResult<Map<String, Object>> serviceResult = handlerJump(processInstanceId, taskId, jumpTaskKey,
                variables);
        if (serviceResult.isSuccess()) {
            processCoreService.backProcess(taskId, jumpTaskKey, variables);
            result.setMsg("操作成功！");
        } else {
            result.setError("操作失败！失败原因：" + serviceResult.getMessage());
        }
        map.clear();
        return result;
    }

    /**
     * @Destribution 审批申请详情
     * @param processInstanceId 流程实例ID
     * @return
     */
    @GetMapping(value = "detail/{processInstanceId}")
    public String detail(@PathVariable String processInstanceId) {
        map.put("processInstanceId", processInstanceId);
        map.put("logList", wfLogsService.findByProcInstId(processInstanceId));
        String path = processDetail(processInstanceId);
        return StringUtil.isEmpty(path) ? "Detail.html" : path;
    }

    private List<ActivityImpl> nextAllTaskDefinition(ActivityImpl activityImpl, String activityId) {
        PvmActivity ac = null;
        List<ActivityImpl> taskList = new ArrayList<ActivityImpl>();
        // 如果遍历节点为用户任务并且节点不是当前节点信息
        if (("userTask".equals(activityImpl.getProperty("type")) || "endEvent".equals(activityImpl.getProperty("type")))
                && !activityId.equals(activityImpl.getId())) {
            taskList.add(activityImpl);
        } else {
            // 获取节点所有流向线路信息
            List<PvmTransition> outTransitions = activityImpl.getOutgoingTransitions();
            for (PvmTransition tr : outTransitions) {
                ac = tr.getDestination(); // 获取线路的终点节点
                for (PvmTransition tr1 : ac.getOutgoingTransitions()) {
                    List<ActivityImpl> tmpList = childTaskDefinition((ActivityImpl) tr1.getDestination(), activityId);
                    List<ActivityImpl> restList = new ArrayList<ActivityImpl>();
                    boolean isChild = true;
                    while (isChild) {
                        for (int i = 1; i < tmpList.size(); i++) {
                            restList.add(tmpList.get(i));
                        }
                        ActivityImpl childActivityImpl = tmpList.get(0);
                        if (!taskList.contains(childActivityImpl)) {
                            taskList.add(tmpList.get(0));
                        }
                        if (!"endEvent".equals(childActivityImpl.getProperty("type"))) {
                            tmpList = childTaskDefinition(tmpList.get(0), tmpList.get(0).getId());
                        } else if (restList != null && restList.size() > 0) {
                            tmpList = childTaskDefinition(restList.get(0), restList.get(0).getId());
                            restList.remove(0);
                        } else {
                            tmpList = null;
                            isChild = false;
                        }
                    }
                }
                if ("userTask".equals(ac.getProperty("type")) || "endEvent".equals(ac.getProperty("type"))) {
                    taskList.add((ActivityImpl) ac);
                }
            }
        }
        return taskList;
    }

    private List<ActivityImpl> childTaskDefinition(ActivityImpl activityImpl, String activityId) {
        PvmActivity ac = null;
        List<ActivityImpl> taskList = new ArrayList<ActivityImpl>();
        // 如果遍历节点为用户任务并且节点不是当前节点信息
        if (("userTask".equals(activityImpl.getProperty("type")) || "endEvent".equals(activityImpl.getProperty("type")))
                && !activityId.equals(activityImpl.getId())) {
            taskList.add(activityImpl);
        } else {
            // 获取节点所有流向线路信息
            List<PvmTransition> outTransitions = activityImpl.getOutgoingTransitions();
            for (PvmTransition tr : outTransitions) {
                ac = tr.getDestination(); // 获取线路的终点节点
                // 如果流向线路为排他网关
                if ("exclusiveGateway".equals(ac.getProperty("type"))) {
                    for (PvmTransition tr1 : ac.getOutgoingTransitions()) {
                        List<ActivityImpl> tmpList = childTaskDefinition((ActivityImpl) tr1.getDestination(),
                                activityId);
                        taskList.addAll(tmpList);
                    }
                } else if ("userTask".equals(ac.getProperty("type")) || "endEvent".equals(ac.getProperty("type"))) {
                    taskList.add((ActivityImpl) ac);
                }
            }
        }
        return taskList;
    }
}
